home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 007a / cug315.zip / FTGRAPH.C < prev    next >
Text File  |  1990-05-16  |  35KB  |  1,492 lines

  1. /* modified 11/89 by T Clune to allow override of autoscaling on graphs. */
  2. /* This lets the user set two or more graphs to the same scale if he likes. */
  3. /* See readme.txt for details on usage. */ 
  4.  
  5. /* modified 10/89 to use MSHERC.COM for Hercules support instead of my */
  6. /* Hercules driver.  Microsoft verified that MSHERC.COM can be distributed */
  7. /* with applications without infringing on their rights, 10/89. */
  8. /* Also, changed to accept defaults for all inputs as a mouse support */
  9. /* feature.  In addition, mgetch() and mgets() from MENU.C are now used */
  10. /* to automatically determine whether the mouse is being supported for */
  11. /* input, instead of changing the function pointers for input statements */
  12. /* depending on how mouse_flag is initialized.  Since the function pointers */
  13. /* have not been removed, this change is essentially meaningless here. */
  14. /* Modified by T Clune */
  15.  
  16. /* Modified 4/89 by Tom Clune to circumvent some versions of DOS that */
  17. /* do not contain the filespec of the program in ARGV[0].  graph_init() */
  18. /* first tries the argv[0] value, and if that fails, tries the name in */
  19. /* the #define, which is the filename with no  path (i.e., requires that */
  20. /* you use the default path for the config file) value before aborting. */
  21. /* Because the name is in FTGRAPH.H, you must edit FTGRAPH.H to use the */
  22. /* name you will be using for the program before compiling. */
  23.  
  24. /* modified 4/89 by Tom Clune to support CGA, VGA, and EGA graphics */
  25. /* to link the program, use: LINK FTGRAPH,,,FTPLOT MOUSELIB MOUSE GRAPHICS */
  26. /* Note that the library GRAPHICS of MS C v. 5.1 must be invoked */
  27. /* explicitly during linking.  Similarly, for the no-mouse version */
  28. /* of ftgraph, link: FTGRAPH,,,FTPLOT NONMOUSE GRAPHICS. */
  29.  
  30. /* Written 3/89 by T Clune to plot FFT and IFT data. */
  31. /* ftgraph.c uses text-mode (ASCII-format) data files structured as */
  32. /* follows: Line 1 will contain an integer specifying the number of data */
  33. /* points in the data set and two floating point values, the minimum and */
  34. /* maximum value for the y-axis of the graph.                           */
  35. /* The rest of the file is the floating-point data values, separated by */
  36. /* white-space characters (space, carriage-return/line-feed, or tab). */
  37. /* To compile this program, use Microsoft C, v.5, large memory model. */
  38. /* I compiled it will optimization disabled (as I do for all my programs) */
  39. /* but I have no reason to believe that optimization will cause the */
  40. /* the program to fail. */
  41. /* To run the program, FTGRAPH.CNF must be in the same directory as */
  42. /* FTGRAPH.EXE, and you must have DEVICE=ANSI.SYS in your config.sys file */
  43. /* Copyright (c) 1989, Eye Research Institute.  All Rights Reserved. */
  44.  
  45. #include "mouselib.h"
  46. #include "msc_grph.h"
  47. #include "ansi.h"
  48. #include "fft.h"
  49. #include "hpgl.h"
  50. #include "hpglplot.h"
  51. #include "ftgraph.h"
  52. #include "menu.h"
  53. #include "keys.h"
  54. #include <stdlib.h>
  55. #include <process.h>
  56. #include <graph.h>
  57. #include <malloc.h>
  58. #include <math.h>
  59. #include <stdio.h>
  60. #include <conio.h>
  61. #include <string.h>
  62.  
  63. static void graph_init(), reset_options(), ft(), graph_out(), correlate();
  64. static void write_data(), ft_multiply(), autopower(), crosspower();
  65. static int ft_process(), binary_choice();
  66. static void ft_save(), display_menu(), printout(), peak_extract();
  67. static char *get_prompt();
  68. static double *get_data();
  69. static void filter_main(), ft_filter();
  70. static getsfuncptr get_string;
  71. static intptr pause_func;
  72.  
  73. static double min_amp, filter_units;
  74. static int ft_coords, ft_pos_neg, ft_precis, mouse_flag;
  75.  
  76. void main(argc, argv)
  77. int argc;
  78. char *argv[];
  79. {
  80.     FILE *f;
  81.  
  82.     static char *options[] =
  83.     {
  84.     "Quit",
  85.     "Reset options",
  86.     "Forward transform (file output)",
  87.     "Inverse transform (file output)",
  88.     "Multiply two data files (file output)",
  89.     "Auto-power spectrum (file output)",
  90.     "Cross-power spectrum (file output)",
  91.     "Correlation from power spectrum data (file output)",
  92.     "Filter time-domain real data (file output)",
  93.     "Display data file (HPGL, graphics screen, or printer)"
  94.     };
  95.  
  96.     /* menu parameters.  See menu.c documentation */
  97.     int top, left, tab, columns, spacing, entries, auto_label;
  98.  
  99.     int choice; /* menu selection variable */
  100.     top=3;      /* initialize menu variables */
  101.     left=20;
  102.     tab=0;
  103.     columns=1;
  104.     spacing=2;
  105.     entries=10;
  106.     auto_label= -2;
  107.  
  108.     graph_init(argv[0]);
  109.  
  110.     /* if mouse enabled, set menu variable for mouse operation */
  111.     if(mouse_flag==MOUSE_ON)
  112.     mouse_flag_toggle(MOUSE_PLUS_KEYBOARD);
  113.  
  114.     reset_menu(0);
  115.  
  116.     for(;;)
  117.     {
  118.         /* CLS, POSITION, and CHAR_ATTRIBUTE are ANSI.H macros */
  119.     CLS;
  120.  
  121.     POSITION(20,1); /* center heading */
  122.     CHAR_ATTRIBUTE(UNDERSCORE);
  123.  
  124.     printf("MAIN MENU -- FFT GRAPHING FUNCTIONS\n");
  125.  
  126.     CHAR_ATTRIBUTE(NORMAL);
  127.  
  128.     while(kbhit())
  129.         getch();
  130.  
  131.  
  132.         /* get a menu selection */
  133.     choice=menu(top,left,tab,columns,spacing,entries,auto_label,options);
  134.  
  135.     switch(choice)  /* see the OPTION strings for meaning of choice */
  136.     {
  137.         case 0:
  138.             CLS;
  139.             exit(0);
  140.         case 1:
  141.             CLS;
  142.             reset_options();
  143.             reset_menu(choice);
  144.             break;
  145.         case 2:
  146.             CLS;
  147.             ft(FORWARD);
  148.             reset_menu(choice);
  149.             break;
  150.         case 3:
  151.             CLS;
  152.             ft(INVERSE);
  153.             reset_menu(choice);
  154.             break;
  155.         case 4:
  156.             CLS;
  157.             ft_multiply();
  158.             reset_menu(choice);
  159.             break;
  160.         case 5:
  161.             CLS;
  162.             autopower();
  163.             reset_menu(choice);
  164.             break;
  165.  
  166.         case 6:
  167.             CLS;
  168.             crosspower();
  169.             reset_menu(choice);
  170.             break;
  171.         case 7:
  172.             CLS;
  173.             correlate();
  174.             reset_menu(choice);
  175.             break;
  176.         case 8:
  177.             CLS;
  178.             filter_main();
  179.             reset_menu(choice);
  180.             break;
  181.         case 9:
  182.             CLS;
  183.             display_menu();
  184.             reset_menu(choice);
  185.             break;
  186.         default:
  187.             break;
  188.  
  189.     }
  190.  
  191.     }
  192.  
  193. }
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200. /* autopower() performs an auto power spectrum on the selected data */
  201.  
  202. static void autopower()
  203. {
  204.     static double *x, *y, *minval, *maxval;
  205.     static string_struc f;
  206.     static int n;
  207.     int i;
  208.     char c;
  209.     int coords;
  210.  
  211.     CLS;
  212.     printf("This auto power routine asks only for the real data set.\n");
  213.     printf("NOTE WELL:  The autopower FT has different units than a normal FT, and is\n");
  214.     printf("called variously an auto spectrum, a power spectrum or the power spectral\n");
  215.     printf("density of the data set.\n");
  216.     printf("NOTICE: Since a power spectrum is defined relative to the area under\n");
  217.     printf("the PSD AMPLITUDE graph, this routine produces polar format output,\n");
  218.     printf("no matter what coordinate system you are using for FTs.\n");
  219.     printf("Phase data for a power spectrum is meaningless, and will not be saved\n");
  220.     printf("The inverse FT of this routine's output is called an autocorrelation\n");
  221.     printf("and is a measure of the extent to which the data set is self-similar\n");
  222.     printf("If you want to inverse-transform the output, you should make sure\n");
  223.     printf("that you have positive/negative selected for your transform option.\n");
  224.     printf("Because of the way that various flags internal to the program are set,\n");
  225.     printf("you should use the CORRELATION menu option instead of INVERSE TRANSFORM\n");
  226.     printf("to obtain the correlation IFT.\n");
  227.     printf("The IFT (auto-correlation) will have 0 lag in center-screen.\n");
  228.     printf("0 lag is perfect correlation (unshifted data correlates exactly to itself)\n\n");
  229.     printf("Now, select the data file.  Press any key to continue.\n");
  230.     (* pause_func)();
  231.  
  232.     coords=ft_coords;
  233.     ft_coords=POWER;
  234.  
  235.     do
  236.     {
  237.     f=get_file();
  238.     if(f.error_flag != 0)
  239.     {
  240.         printf("Do you want to abort this function and return to the main menu (y/N)?\n");
  241.         c=binary_choice('N','Y');
  242.         if(c=='Y')
  243.         {
  244.         ft_coords=coords;
  245.         return;
  246.         }
  247.     }
  248.     }while(f.error_flag != 0);
  249.  
  250.     x=get_data(f.string,x,&n,minval, maxval);
  251.  
  252.     y=(double *)calloc(n, sizeof(double));
  253.     if(y==NULL)
  254.     {
  255.     printf("Error allocating memory.  Program aborting.\n");
  256.     exit(-1);
  257.     }
  258.  
  259.     n=ft_process(x,y,n,FORWARD);
  260.  
  261.     /* square the transform for the power spectrum */
  262.     for(i=0;i<n;i++)
  263.     {
  264.     x[i] = x[i]*x[i]+y[i]*y[i];
  265.     y[i] =0.0;
  266.     }
  267.  
  268.     ft_save(x,y,n,FORWARD);
  269.  
  270.     free(x);
  271.     free(y);
  272.     ft_coords=coords;
  273.  
  274. }
  275.  
  276.  
  277.  
  278. /* binary_choice() is a generic input for y/n-type responses, in which */
  279. /* PRIMARY is the default value if <CR> or (assuming that it is active) */
  280. /* RIGHT mouse button is pressed, and ALTERNATE is the other valid input. */
  281. /* The prompt that is to be printed for binary_choice() is separate */
  282. /* from this function. */
  283.  
  284. static int binary_choice(primary, alternate)
  285. int primary, alternate;
  286. {
  287.     int c;
  288.     primary=toupper(primary);
  289.     alternate=toupper(alternate);
  290.  
  291.     while((c=(toupper((* pause_func)()))) != primary && c != alternate && c != CARRIAGE_RETURN)
  292.     error_msg();
  293.  
  294.     if(c==CARRIAGE_RETURN)
  295.     c=primary;
  296.  
  297.     return c;
  298.  
  299. }
  300.  
  301.  
  302.  
  303.  
  304.  
  305. /* correlate() performs an auto- or cross-correlation from spectra generated */
  306. /* by autopower() or crosspower() under the pos/neg spectra option */
  307.  
  308. static void correlate()
  309. {
  310.     int coords;
  311.  
  312.     coords=ft_coords;
  313.     ft_coords=POWER;
  314.  
  315.     CLS;
  316.     printf("In order to perform a correlation, you must use data files that\n");
  317.     printf("were generated by the AUTO POWER or CROSS POWER option ONLY. In addition,\n");
  318.     printf("the spectra must have used the pos/neg frequencies format for the\n");
  319.     printf("correlation data to represent the same time units as the original spectrum.\n\n");
  320.     printf("Press any key to begin...\n");
  321.     (* pause_func)();
  322.     ft(INVERSE);
  323.     ft_coords=coords;
  324.  
  325.  
  326. }
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333. /* crosspower() performs an cross-power spectrum on the selected data sets */
  334.  
  335. static void crosspower()
  336. {
  337.     static double *x1, *y1, *x2, *y2;
  338.     static double *minval, *maxval;
  339.     static string_struc f;
  340.     static int n,m;
  341.     int i;
  342.     char c;
  343.     int coords;
  344.  
  345.  
  346.     CLS;
  347.     printf("This cross-power spectrum routine asks only for the two real data sets.\n");
  348.     printf("NOTE WELL: the units of the cross-power data set are not equivalent to\n");
  349.     printf("those of a normal FT.  The cross-power data set FT is\n");
  350.     printf("called variously a cross spectrum, a power spectrum, or a cross power spectrum.\n");
  351.     printf("NOTICE: Since a power spectrum is defined relative to the area under\n");
  352.     printf("the PSD AMPLITUDE graph, this routine produces polar format output,\n");
  353.     printf("no matter what coordinate system you are using for FTs.\n");
  354.     printf("Phase data for a power spectrum is meaningless, and will not be saved\n");
  355.     printf("The inverse FT of this routine's output is called a cross-correlation.\n");
  356.     printf("If you want to inverse-transform the output, you should make sure\n");
  357.     printf("that you have positive/negative selected for your transform option.\n");
  358.     printf("Because of the way that various flags internal to the program are set,\n");
  359.     printf("you should use the CORRELATION menu option instead of INVERSE TRANSFORM\n");
  360.     printf("to obtain the correlation IFT.\n");
  361.     printf("The IFT (cross-correlation) will have 0 lag in center-screen.\n\n");
  362.     printf("Now, select the first data file.  Press any key to continue.\n");
  363.     (* pause_func)();
  364.     CLS;
  365.  
  366.     coords=ft_coords;
  367.     ft_coords=POWER;
  368.  
  369.  
  370.     do
  371.     {
  372.     f=get_file();
  373.     if(f.error_flag != 0)
  374.     {
  375.         printf("Do you want to abort this function and return to the main menu (y/N)?\n");
  376.         c=binary_choice('N','Y');
  377.         if(c=='Y')
  378.         {
  379.         ft_coords=coords;
  380.         return;
  381.         }
  382.     }
  383.     }while(f.error_flag != 0);
  384.  
  385.     x1=get_data(f.string,x1,&n,minval, maxval);
  386.  
  387.     y1=(double *)calloc(n, sizeof(double));
  388.     if(y1==NULL)
  389.     {
  390.     printf("Error allocating memory.  Program aborting.\n");
  391.     exit(-1);
  392.     }
  393.  
  394.     CLS;
  395.     printf("Now, select the second file for cross-analysis.  Press any key to continue.\n");
  396.     (* pause_func)();
  397.     CLS;
  398.     do
  399.     {
  400.     f=get_file();
  401.     if(f.error_flag != 0)
  402.     {
  403.         printf("Do you want to abort this function and return to the main menu (y/N)?\n");
  404.         c=binary_choice('N','Y');
  405.         if(c=='Y')
  406.         {
  407.         ft_coords=coords;
  408.         free(x1);
  409.         free(y1);
  410.         return;
  411.         }
  412.     }
  413.     }while(f.error_flag != 0);
  414.  
  415.     x2=get_data(f.string,x2,&m,minval, maxval);
  416.  
  417.     if(n != m)
  418.     {
  419.     printf("The two data files are not the same size. Press any key to exit routine \n");
  420.     (* pause_func)();
  421.     free(x1);
  422.     free(y1);
  423.     free(x2);
  424.     ft_coords=coords;
  425.     return;
  426.     }
  427.  
  428.     CLS;
  429.  
  430.     y2=(double *)calloc(m, sizeof(double));
  431.     if(y2==NULL)
  432.     {
  433.     printf("Error allocating memory.  Program aborting.\n");
  434.     exit(-1);
  435.     }
  436.  
  437.     n=ft_process(x1,y1,n,FORWARD);
  438.     m=ft_process(x2,y2,m,FORWARD);
  439.  
  440.     for(i=0;i<n;i++)
  441.     {
  442.     x1[i] =x1[i]*x2[i]+y1[i]*y2[i];
  443.     y1[i] =0.0;
  444.     }
  445.  
  446.     ft_save(x1,y1,n,FORWARD);
  447.  
  448.     free(x1);
  449.     free(y1);
  450.     free(x2);
  451.     free(y2);
  452.     ft_coords=coords;
  453.  
  454. }
  455.  
  456.  
  457.  
  458.  
  459. /* display_menu() provides the various data display options */
  460.  
  461. static void display_menu()
  462. {
  463.     FILE *f;
  464.  
  465.     static char *options[] =
  466.     {
  467.     "Return to Main menu",
  468.     "HPGL bar chart (file output)",
  469.     "HPGL line graph (file output)",
  470.     "Bar chart display of file data (graphics screen)",
  471.     "Line chart display of file data (graphics screen)",
  472.     "Print data file to printer"
  473.     };
  474.  
  475.     /* menu parameters.  See menu.c documentation */
  476.     int top, left, tab, columns, spacing, entries, auto_label;
  477.  
  478.     int choice; /* menu selection variable */
  479.     top=4;      /* initialize menu variables */
  480.     left=20;
  481.     tab=0;
  482.     columns=1;
  483.     spacing=2;
  484.     entries=6;
  485.     auto_label= -2;
  486.  
  487.     reset_menu(0);
  488.  
  489.     for(;;)
  490.     {
  491.         /* CLS, POSITION, and CHAR_ATTRIBUTE are ANSI.H macros */
  492.     CLS;
  493.  
  494.     POSITION(20,1); /* center heading */
  495.     CHAR_ATTRIBUTE(UNDERSCORE);
  496.  
  497.     printf("FFT DATA DISPLAY FUNCTIONS\n");
  498.  
  499.     CHAR_ATTRIBUTE(NORMAL);
  500.  
  501.     while(kbhit())
  502.         getch();
  503.  
  504.  
  505.         /* get a menu selection */
  506.     choice=menu(top,left,tab,columns,spacing,entries,auto_label,options);
  507.  
  508.     switch(choice)  /* see the OPTION strings for meaning of choice */
  509.     {
  510.         case 0:
  511.             CLS;
  512.             return;
  513.             break;
  514.         case 1:
  515.             CLS;
  516.             graph_out(HPGL_BAR);
  517.             reset_menu(choice);
  518.             break;
  519.         case 2:
  520.             CLS;
  521.             graph_out(HPGL_LINE);
  522.             reset_menu(choice);
  523.             break;
  524.         case 3:
  525.             CLS;
  526.             graph_out(GRAPH_BAR);
  527.             reset_menu(choice);
  528.             break;
  529.         case 4:
  530.             CLS;
  531.             graph_out(GRAPH_LINE);
  532.             reset_menu(choice);
  533.             break;
  534.         case 5:
  535.             CLS;
  536.             printout();
  537.             reset_menu(choice);
  538.             break;
  539.         default:
  540.             break;
  541.  
  542.     }
  543.  
  544.     }
  545.  
  546. }
  547.  
  548.  
  549.  
  550.  
  551.  
  552.  
  553.  
  554. /* filter_main() is the main selection menu for filtering options */
  555.  
  556. static void filter_main()
  557. {
  558.     static char *options[] =
  559.     {
  560.     "Return to Main menu",
  561.     "Low-pass filter",
  562.     "High-pass filter"
  563.     };
  564.  
  565.     /* menu parameters.  See menu.c documentation */
  566.     int top, left, tab, columns, spacing, entries, auto_label;
  567.  
  568.     int choice; /* menu selection variable */
  569.     top=4;      /* initialize menu variables */
  570.     left=20;
  571.     tab=0;
  572.     columns=1;
  573.     spacing=2;
  574.     entries=3;
  575.     auto_label= -2;
  576.  
  577.     reset_menu(0);
  578.  
  579.     for(;;)
  580.     {
  581.         /* CLS, POSITION, and CHAR_ATTRIBUTE are ANSI.H macros */
  582.     CLS;
  583.  
  584.     POSITION(20,1); /* center heading */
  585.     CHAR_ATTRIBUTE(UNDERSCORE);
  586.  
  587.     printf("FFT FILTERING MENU\n");
  588.  
  589.     CHAR_ATTRIBUTE(NORMAL);
  590.  
  591.     while(kbhit())
  592.         getch();
  593.  
  594.  
  595.         /* get a menu selection */
  596.     choice=menu(top,left,tab,columns,spacing,entries,auto_label,options);
  597.  
  598.     switch(choice)  /* see the OPTION strings for meaning of choice */
  599.     {
  600.         case 0:
  601.             CLS;
  602.             return;
  603.             break;
  604.         case 1:
  605.             CLS;
  606.             ft_filter(LOWPASS);
  607.             reset_menu(choice);
  608.             break;
  609.         case 2:
  610.             CLS;
  611.             ft_filter(HIGHPASS);
  612.             reset_menu(choice);
  613.             break;
  614.         default:
  615.             break;
  616.     }
  617.  
  618.     }
  619.  
  620. }
  621.  
  622.  
  623.  
  624.  
  625.  
  626. /* ft() keeps track of what kind of spectrum is being transformed, */
  627. /* and shuffling the data file as appropriate for the particular format */
  628. /* of data used.  FLAG specifies a forward or inverse transform */
  629.  
  630. static void ft(flag)
  631. int flag;
  632. {
  633.     static double *x, *y;
  634.     static double *minval, *maxval;
  635.     static string_struc f;
  636.     int i;
  637.     static int n,m;
  638.     char str1[20], str2[20], string[80], c;
  639.  
  640.  
  641.     CLS;
  642.     strcpy(str1,get_prompt(flag, 1));
  643.     strcpy(str2,get_prompt(flag, 2));
  644.  
  645.     printf("First, get the %s component data file.  Press any key to continue.\n",str1);
  646.     (* pause_func)();
  647.     do
  648.     {
  649.     f=get_file();
  650.     if(f.error_flag != 0)
  651.     {
  652.         printf("Do you want to abort this function and return to the main menu (y/N)?\n");
  653.         c=binary_choice('N','Y');
  654.         if(c=='Y')
  655.         return;
  656.     }
  657.     }while(f.error_flag != 0);
  658.  
  659.     x=get_data(f.string,x,&m,minval, maxval);
  660.  
  661.     if(ft_coords != POWER)
  662.     {
  663.     printf("Now, load the %s component data.  You will use the same kind\n", str2);
  664.     printf("of menu as before.  Select the 'Quit' option (last menu item) if you are not\n");
  665.     printf("going to enter a second data component array.\n");
  666.     printf("Press any key to continue\n");
  667.     (* pause_func)();
  668.     CLS;
  669.     do
  670.     {
  671.         f=get_file();
  672.     }while(f.error_flag < 0);
  673.  
  674.     }
  675.     if(ft_coords !=POWER && f.error_flag==0)
  676.     y=get_data(f.string, y, &n,minval, maxval);
  677.     else
  678.     {
  679.     y=(double *)calloc(m, sizeof(double));
  680.     if(y==NULL)
  681.     {
  682.         printf("Error allocating memory.  Program aborting.\n");
  683.         exit(-1);
  684.     }
  685.     n=m;
  686.     }
  687.     if(n != m)
  688.     {
  689.     printf("The two data files are not the same size. Press any key to exit routine \n");
  690.     (* pause_func)();
  691.     free(x);
  692.     free(y);
  693.     return;
  694.     }
  695.  
  696.     n=ft_process(x,y,n,flag);
  697.     ft_save(x,y,n,flag);
  698.  
  699.     if(ft_coords==POWER && flag==INVERSE)
  700.     peak_extract(x,n);
  701.  
  702.     free(x);
  703.     free(y);
  704.  
  705. }
  706.  
  707.  
  708.  
  709. /* ft_filter() creates a filter according to user input and filters the */
  710. /* selected data file by transforming it to the frequency domain and */
  711. /* multiplying by the filter, then inverse transforming the result back to */
  712. /* the time domain. */
  713.  
  714. static void ft_filter(flag)
  715. int flag;
  716. {
  717.  
  718.     static double *x, *y, *filter, *minval, *maxval;
  719.     double rate, cutoff, rolloff;
  720.     static string_struc f;
  721.     char string[80], c;
  722.     int i,sign;
  723.     static int n;
  724.     int pos_neg;
  725.     int coords;
  726.  
  727.     printf("First, get the time-domain data file for filtering.  Press any key...\n");
  728.     (* pause_func)();
  729.     do
  730.     {
  731.     f=get_file();
  732.     if(f.error_flag != 0)
  733.     {
  734.         printf("Do you want to abort this function and return to the main menu (y/N)?\n");
  735.         c=binary_choice('N','Y');
  736.         if(c=='Y')
  737.         return;
  738.     }
  739.     }while(f.error_flag != 0);
  740.  
  741.     x=get_data(f.string,x,&n,minval, maxval);
  742.  
  743.     y=(double *)calloc(n, sizeof(double));
  744.     if(y==NULL)
  745.     {
  746.     printf("Error allocating memory.  Program aborting.\n");
  747.     exit(-1);
  748.     }
  749.  
  750.     CLS;
  751.     printf("Now, enter the sampling frequency (reciprocal of the sampling rate)\n");
  752.     printf("(e.g., if you collected data every 1/100 of a second, enter 100.0)\n");
  753.     while((rate=atof((* get_string)(string)))<=0.0)
  754.     error_msg();
  755.  
  756.     /* turn sampling frequency into Nyquist limit */
  757.     rate /= 2.0;
  758.  
  759.     CLS;
  760.     printf("Enter the cutoff frequency for the filter, in Hz\n");
  761.     while((cutoff=atof((* get_string)(string)))<=0.0)
  762.     error_msg();
  763.  
  764.     if(cutoff>=rate)
  765.     {
  766.     printf("Cutoff frequency exceeds Nyquist limit of data set.  Press any key...\n");
  767.     (* pause_func)();
  768.     free(x);
  769.     free(y);
  770.     return;
  771.     }
  772.  
  773.     CLS;
  774.     printf("Enter the rolloff in ");
  775.     if(filter_units==10.0)
  776.     printf("dB/decade for the filter (POSITIVE number only)\n");
  777.     else
  778.     printf("dB/octave for the filter (POSITIVE number only)\n");
  779.     while((rolloff=atof((* get_string)(string)))<=0.0)
  780.     error_msg();
  781.  
  782.     pos_neg=ft_pos_neg;
  783.     ft_pos_neg=ALL;
  784.     coords=ft_coords;
  785.     ft_coords=AMP;
  786.  
  787.     filter=(double *)calloc(n, sizeof(double));
  788.     if(filter==NULL)
  789.     {
  790.     printf("Error allocating memory.  Program aborting.\n");
  791.     exit(-1);
  792.     }
  793.  
  794.     if(flag==LOWPASS)
  795.     sign= -1;
  796.     else
  797.     sign= 1;
  798.  
  799.     filter=get_filter(filter,n,sign,rate,cutoff,rolloff,filter_units);
  800.  
  801.     CLS;
  802.     printf("We will now do the filtering.  Press any key...\n");
  803.     (* pause_func)();
  804.  
  805.     n=ft_process(x,y,n,FORWARD);
  806.  
  807.     for(i=0;i<n;i++)
  808.     x[i]=x[i]*filter[i];
  809.  
  810.     n=ft_process(x,y,n,INVERSE);
  811.     ft_save(x,y,n,INVERSE);
  812.  
  813.     CLS;
  814.     printf("Do you want a POLAR FORMAT frequency-domain file of the filter (y/N)?\n");
  815.     c=binary_choice('N','Y');
  816.  
  817.     if(c=='Y')
  818.     {
  819.     for(i=0;i<n;i++)
  820.         y[i]=0.0;
  821.     if(pos_neg==ALL)
  822.         ft_save(filter,y,n,FORWARD);
  823.     else
  824.         ft_save(&filter[n/2],&y[n/2],n/2,FORWARD);
  825.     }
  826.  
  827.     ft_coords=coords;
  828.     ft_pos_neg=pos_neg;
  829.     free(x);
  830.     free(y);
  831.     free(filter);
  832.  
  833. }
  834.  
  835.  
  836.  
  837.  
  838.  
  839.  
  840. /* ft_multiply() gets two data files to multiply together */
  841.  
  842. static void ft_multiply()
  843. {
  844.     char str[2][80];
  845.     int i, c;
  846.     string_struc f;
  847.  
  848.     CLS;
  849.     for(i=0;i<2;i++)
  850.     {
  851.     do
  852.     {
  853.         f=get_file();
  854.         if(f.error_flag != 0)
  855.         {
  856.         printf("Do you want to abort this function and return to the main menu (y/N)?\n");
  857.         c=binary_choice('N','Y');
  858.         if(c=='Y')
  859.             return;
  860.         }
  861.     }while(f.error_flag != 0);
  862.  
  863.     strcpy(str[i], f.string);
  864.     }
  865.  
  866.     data_multiply(str[0], str[1]);
  867.  
  868. }
  869.  
  870.  
  871.  
  872.  
  873. /* ft_process() does the actual calling of the FT, and keeps track of whether */
  874. /* this is a foreward or inverse transform, and reshuffles the data accordingly */
  875.  
  876. static int ft_process(x,y,n,flag)
  877. double x[], y[];
  878. int n,flag;
  879. {
  880.  
  881.     CLS;
  882.     printf("Processing...");
  883.  
  884.     /* put the order back the way it was in the transform */
  885.     if((flag==INVERSE) && (ft_pos_neg==ALL))
  886.     {
  887.     unscramble_transform(x,n);
  888.     unscramble_transform(y,n);
  889.     }
  890.  
  891.     if((flag==INVERSE) && (ft_coords == AMP))
  892.     polar_to_xy(x,y,x,y,n);
  893.  
  894.     fft(x,y,n,flag);
  895.  
  896. /* power,phase IFTs are shifted with this transform, & must be unshifted */
  897.  
  898.     if((flag==INVERSE) && (ft_coords == POWER))
  899.     {
  900.     unscramble_transform(x,n);
  901.     unscramble_transform(y,n);
  902.     }
  903.  
  904.  
  905.     if(flag==FORWARD)
  906.     {
  907.     if(ft_pos_neg==ALL)
  908.     {
  909.         unscramble_transform(x,n);
  910.         unscramble_transform(y,n);
  911.     }
  912.     else
  913.         n /=2;
  914.  
  915.     if(ft_coords == AMP)
  916.         xy_to_polar(x,y,x,y,n,min_amp);
  917.  
  918.     }
  919.     return n;
  920. }
  921.  
  922.  
  923.  
  924.  
  925.  
  926.  
  927. /* ft_save() is the front-end for saving FT data files */
  928.  
  929. static void ft_save(x,y,n,flag)
  930. double x[], y[];
  931. int n, flag;
  932. {
  933.  
  934.     char str1[20], str2[20], string[80];
  935.  
  936.     flag *= (-1);
  937.     strcpy(str1,get_prompt(flag, 1));
  938.     strcpy(str2,get_prompt(flag, 2));
  939.  
  940.     CLS;
  941.     while(kbhit())
  942.     getch();
  943.     printf("Enter the filespec for the %s data file or <CR> to discard\n", str1);
  944.     (* get_string)(string);
  945.     if(strlen(string))
  946.     write_data(string,x,n);
  947.     while(kbhit())
  948.     getch();
  949.     if(ft_coords != POWER)
  950.     {
  951.     printf("Enter the filespec for the %s data file or <CR> to discard\n", str2);
  952.     (* get_string)(string);
  953.     if(strlen(string))
  954.         write_data(string,y,n);
  955.     }
  956.  
  957. }
  958.  
  959.  
  960.  
  961.  
  962. /* get_data() reads a data file and allocates memory to load it into. */
  963. /* STRING is the file name, X is the pointer to the dat array, M is a */
  964. /* pointer to the counter for number of elements in the data array, MINVAL */
  965. /* is a pointer to the min data file value variable, and MAXVAL points to */
  966. /* the max. data file value variable.  The routine automatically zero-fills */
  967. /* data sets that are not a power of 2. */
  968.  
  969. static double *get_data(string, x, m, minval, maxval)
  970. char string[];
  971. double *x;
  972. int *m;
  973. double *minval, *maxval;
  974. {
  975.     FILE *fi;
  976.     int i=0;
  977.     static int n;
  978.     unsigned int mask=0x8000;
  979.  
  980.    /* the I counter is to try to circumvent floppy disk opening errors */
  981.     do
  982.     {
  983.     fi=fopen(string,"r");
  984.     i++;
  985.     }while(fi==NULL && i<4);
  986.  
  987.     if(fi==NULL)
  988.     {
  989.     printf("Error opening data file %s\n.", string);
  990.     perror("Program aborting");
  991.     exit(-1);
  992.     }
  993.     fscanf(fi,"%d %lg %lg",&n, minval, maxval);
  994.  
  995.     while(!(mask & n))
  996.     mask /=2;
  997.  
  998.     if((mask & n) != n)
  999.     {
  1000.     printf("NOTICE: Number of points in data file is not a power of 2.\n");
  1001.     printf("The program will zero-fill the %d data points to make a %u point set\n", n, mask*2);
  1002.     printf("Press any key to continue\n");
  1003.     (* pause_func)();
  1004.     CLS;
  1005.     mask *=2;
  1006.     }
  1007.  
  1008.     x=(double *)calloc(mask,sizeof(double));
  1009.     if(x==NULL)
  1010.     {
  1011.     printf("Error allocating memory.  Program aborting.\n");
  1012.     exit(-1);
  1013.     }
  1014.     for(i=0;i<n;i++)
  1015.     fscanf(fi,"%lg",&x[i]);
  1016.     fclose(fi);
  1017.  
  1018.     *m=mask;
  1019.  
  1020.     return x;
  1021.  
  1022. }
  1023.  
  1024.  
  1025.  
  1026.  
  1027.  
  1028.  
  1029. /* get_prompt() assigns a string for ft() prompts.  FLAG tells whether */
  1030. /* the prompt is for FORWARD or INVERSE data files, TERM says whether it is */
  1031. /* the x or y data file prompt. */
  1032.  
  1033. static char *get_prompt(flag, term)
  1034. int flag, term;
  1035. {
  1036.     int i;
  1037.     static char string[20];
  1038.  
  1039.     if(term==1)
  1040.     {
  1041.  
  1042.     if((flag==FORWARD)|| (ft_coords==XY))
  1043.         strcpy(string, "Real");
  1044.     else
  1045.         if(ft_coords == AMP)
  1046.         strcpy(string, "Amplitude");
  1047.         else
  1048.         strcpy(string, "Power");
  1049.     }
  1050.     else
  1051.     {
  1052.     if((flag==FORWARD)|| (ft_coords==XY))
  1053.         strcpy(string, "Imaginary");
  1054.     else
  1055.         strcpy(string, "Phase");
  1056.     }
  1057.  
  1058.     return string;
  1059.  
  1060. }
  1061.  
  1062.  
  1063.  
  1064.  
  1065. /* graph_init() reads the configuration file for the program */
  1066. /* and initializes the graphics adaptor variables in msc_grph.c */
  1067.  
  1068. static void graph_init(string)
  1069. char string[];
  1070. {
  1071.     FILE *f;
  1072.     char str[80];
  1073.     char *sptr;
  1074.     int i=0;
  1075.  
  1076.  
  1077.     strcpy(str, string);
  1078.     sptr=strchr(str, '.');
  1079.     sptr++;
  1080.     *sptr='\0';
  1081.     strcat(str, "CNF");
  1082.  
  1083.     /* the I counter is to try to circumvent floppy disk opening errors */
  1084.     do
  1085.     {
  1086.     f=fopen(str, "r");
  1087.     i++;
  1088.     }while(f==NULL && i<4);
  1089.  
  1090.     if(f==NULL)
  1091.     {
  1092.  
  1093.     /* this part is a kludge to get around some versions of DOS that do */
  1094.     /* not pass the filespec in ARGV[0]. */
  1095.  
  1096.     i=0;
  1097.     do
  1098.     {
  1099.         f=fopen(CONFIG_FILE, "r");
  1100.         i++;
  1101.     }while(f==NULL && i<4);
  1102.     }
  1103.  
  1104.     if(f==NULL)
  1105.     {
  1106.     printf("Unable to open initialization file %s.\n", str);
  1107.     perror("Program aborting");
  1108.     exit(-1);
  1109.     }
  1110.     fscanf(f, "%lg %d %d %lg %d %d", &min_amp, &ft_pos_neg, &ft_coords, &filter_units, &ft_precis, &mouse_flag);
  1111.     fclose(f);
  1112.  
  1113.     if(mouse_flag==MOUSE_ON)
  1114.     {
  1115.         /* check that system has a mouse if mouse option activated */
  1116.     i=m_install().opcode;
  1117.     if(i != (-1))
  1118.     {
  1119.         printf("Mouse not found.  Disabling mouse option.\n");
  1120.         printf("Press any key to continue...\n");
  1121.         getch();
  1122.         mouse_flag=0;
  1123.     }
  1124.     }
  1125.     if(mouse_flag==MOUSE_ON)
  1126.     {
  1127.     get_string=mouse_gets;
  1128.     pause_func=inpause;
  1129.     }
  1130.     else
  1131.     {
  1132.     get_string=gets;
  1133.     pause_func=getch;
  1134.     }
  1135.     get_adaptor();
  1136.  
  1137. }
  1138.  
  1139.  
  1140.  
  1141.  
  1142.  
  1143. /* graph_out() draws a graph to the hercules screen or creates an HPGL */
  1144. /* file of the graph, that can then be output to an HP plotter or plotter */
  1145. /* emulator.  FLAG identifies whether the graph goes to screen or to file */
  1146. /* and whether its a bar graph or line graph */
  1147.  
  1148. static void graph_out(flag)
  1149. int flag;
  1150. {
  1151.     static string_struc f;
  1152.     static double *x;
  1153.     static double minval, maxval;
  1154.     static int n;
  1155.     int i;
  1156.     char string[80];
  1157.  
  1158.     CLS;
  1159.     do
  1160.     {
  1161.     f=get_file();
  1162.     }while(f.error_flag != 0);
  1163.  
  1164.     x=get_data(f.string, x, &n, &minval, &maxval);
  1165.  
  1166.     /* verify that min/max were meaningful here */
  1167.     if(minval==maxval)
  1168.     minmax(x,n,&minval,&maxval);
  1169.  
  1170.     if(minval==maxval)
  1171.     {
  1172.     printf("All datapoints have the same value (%lf).  Routine aborting.\n",minval);
  1173.     printf("press any key to continue\n");
  1174.     (* pause_func)();
  1175.     free(x);
  1176.     return;
  1177.     }
  1178.  
  1179.     if(flag==HPGL_BAR)
  1180.     hpgl_bar(x,n,minval,maxval);
  1181.     if(flag==HPGL_LINE)
  1182.     hpgl_graph(x,n,minval,maxval);
  1183.     if(flag==GRAPH_BAR)
  1184.     msc_bar(x,n,minval, maxval);
  1185.     if(flag==GRAPH_LINE)
  1186.     msc_line(x,n,minval,maxval);
  1187.     free(x);
  1188.  
  1189. }
  1190.  
  1191.  
  1192. /* peak_extract() finds and prints the positive lag peaks in descending */
  1193. /* magnitude from a correlation.  Output is to a printer.  X[] is the */
  1194. /* array of time-domain points to order, and N is the number of points */
  1195. /* in the data set. */
  1196.  
  1197. static void peak_extract(x,n)
  1198. double x[];
  1199. int n;
  1200. {
  1201.     int i, j, peak_count=0, zeropt, *index, temp_i;
  1202.     double temp_var, *p_temp, interval;
  1203.     char c, string[80];
  1204.  
  1205.  
  1206.     CLS;
  1207.     printf("Would you like to get a hard-copy printout of positive lag peaks\n");
  1208.     printf("by descending magnitude (y/N)?\n");
  1209.     c=binary_choice('N','Y');
  1210.  
  1211.     if(c=='N')
  1212.     return;
  1213.  
  1214.     p_temp=(double *)malloc(n/2*sizeof(double));
  1215.     index=(int *)malloc(n/2*sizeof(int));
  1216.  
  1217.     if(p_temp==NULL || index==NULL)
  1218.     {
  1219.     printf("Error allocating internal memory.  Program aborting.\n");
  1220.     exit(-1);
  1221.     }
  1222.     CLS;
  1223.     printf("Enter the sampling interval in seconds between datapoints\n");
  1224.     while((interval=(atof((* get_string)(string)))) <=0.0)
  1225.     error_msg();
  1226.  
  1227.     zeropt=n/2;
  1228.  
  1229.     for(i=zeropt;i<n;i++)
  1230.     {
  1231.     if((x[i]>x[i-1]) && (x[i]>=x[i+1]))
  1232.     {
  1233.         p_temp[peak_count]=x[i];
  1234.         index[peak_count]=i-zeropt;
  1235.         peak_count++;
  1236.     }
  1237.  
  1238.     }
  1239.  
  1240.  
  1241.     /* do a bubble sort.  Who cares? */
  1242.     for(i=0;i<(peak_count-1);i++)
  1243.     {
  1244.     for(j=(i+1);j<peak_count;j++)
  1245.     {
  1246.         if(p_temp[j]>p_temp[i])
  1247.         {
  1248.         temp_var=p_temp[i];
  1249.         p_temp[i]=p_temp[j];
  1250.         p_temp[j]=temp_var;
  1251.         temp_i=index[i];
  1252.         index[i]=index[j];
  1253.         index[j]=temp_i;
  1254.         }
  1255.     }
  1256.     }
  1257.  
  1258.     fprintf(stdprn, "TABLE OF CORRELATION PEAKS (POSITIVE LAG ONLY) IN DESCENDING ORDER\n\n");
  1259.     fprintf(stdprn, "Format: lag count, lag in seconds, normalized correlation.\n");
  1260.     fprintf(stdprn,"LAG COUNT is the number of sampling intervals the spectrum was shifted.\n");
  1261.     fprintf(stdprn,"LAG in seconds is just LAG COUNT times the sampling interval.\n\n");
  1262.  
  1263.     temp_var=p_temp[0];
  1264.  
  1265.     for(i=0;i<peak_count;i +=PTS_PER_LINE)
  1266.     {
  1267.     for(j=0;j<PTS_PER_LINE;j++)
  1268.     {
  1269.         if((i+j)<peak_count)
  1270.         fprintf(stdprn,"%d,%.*g,%.*g    ", index[i+j], ft_precis, (double)index[i+j]*interval, ft_precis, p_temp[i+j]/temp_var);
  1271.     }
  1272.     fprintf(stdprn,"\n");
  1273.     }
  1274.  
  1275.     fflush(stdprn);
  1276.  
  1277.     free(p_temp);
  1278.     free(index);
  1279. }
  1280.  
  1281.  
  1282.  
  1283.  
  1284.  
  1285.  
  1286. /* printout() prints a selected data file to the printer */
  1287.  
  1288. static void printout()
  1289. {
  1290.     static double *x, *y, *minval, *maxval;
  1291.     static string_struc f;
  1292.     static int n;
  1293.     double rate, startpt;
  1294.     int i,j;
  1295.     char string[80],c;
  1296.  
  1297.     CLS;
  1298.     printf("First, select the data file for printing.  Press any key to continue.\n");
  1299.     (* pause_func)();
  1300.     do
  1301.     {
  1302.     f=get_file();
  1303.     if(f.error_flag != 0)
  1304.     {
  1305.         printf("Do you want to abort this function and return to the main menu (y/N)?\n");
  1306.         c=binary_choice('N','Y');
  1307.         if(c=='Y')
  1308.         return;
  1309.     }
  1310.     }while(f.error_flag != 0);
  1311.  
  1312.     x=get_data(f.string,x,&n,minval, maxval);
  1313.  
  1314.     CLS;
  1315.     printf("Is this a time domain or a frequency domain file (t/F)?\n");
  1316.     c=binary_choice('F', 'T');
  1317.     CLS;
  1318.  
  1319.     if(c=='T')
  1320.     {
  1321.     printf("Enter the sampling rate in seconds\n");
  1322.     while((rate=atof((* get_string)(string))) <= 0.0)
  1323.         error_msg;
  1324.     startpt=0.0;
  1325.     }
  1326.     else
  1327.     {
  1328.     printf("Enter the Nyquist frequency for the data set\n");
  1329.     while((rate=atof((* get_string)(string))) <= 0.0)
  1330.         error_msg;
  1331.     if(ft_pos_neg==ALL)
  1332.     {
  1333.         startpt= (-rate);
  1334.         rate /=(n/2);
  1335.     }
  1336.     else
  1337.     {
  1338.         startpt = 0.0;
  1339.         rate /=n;
  1340.     }
  1341.     }
  1342.     fprintf(stdprn,"DATAFILE: %s\n\n",f.string);
  1343.     if(c=='T')
  1344.     fprintf(stdprn,"Data in (seconds, magnitude) format\n");
  1345.     else
  1346.     fprintf(stdprn,"Data in (frequency, magnitude) format\n");
  1347.  
  1348.     for(i=0;i<n;i +=PTS_PER_LINE)
  1349.     {
  1350.     for(j=0;j<PTS_PER_LINE;j++)
  1351.     {
  1352.         if((i+j)<n)
  1353.         fprintf(stdprn,"%d. %.*g, %.*g  ",i+j+1, ft_precis, startpt+rate*(i+j),ft_precis, x[i+j]);
  1354.     }
  1355.     fprintf(stdprn,"\n");
  1356.     }
  1357.  
  1358.     fflush(stdprn);
  1359.     free(x);
  1360.  
  1361. }
  1362.  
  1363.  
  1364.  
  1365.  
  1366. /* reset_options() lets you view the current settings for the program and */
  1367. /* allows you to temporarily override the defaults.  To permanently */
  1368. /* change the defaults, edit the .CNF file. */
  1369.  
  1370. static void reset_options()
  1371. {
  1372.     char string[80];
  1373.     int wrong=0;
  1374.  
  1375.     CLS;
  1376.     printf("The FT coordinate system in use is: ");
  1377.     if(ft_coords==XY)
  1378.     printf("real/imaginary\n");
  1379.     if(ft_coords==AMP)
  1380.     printf("Amplitude/phase\n");
  1381.     while(kbhit())
  1382.     getch();
  1383.     printf("Enter 'X' for real/imaginary (x/y), 'A' amplitude/phase, or <CR> for no change\n");
  1384.     do
  1385.     {
  1386.     (* get_string)(string);
  1387.     if(strlen(string) && (toupper(string[0]) != 'X') && (toupper(string[0]) != 'A'))
  1388.         wrong=1;
  1389.     else
  1390.         wrong=0;
  1391.     if(wrong)
  1392.         error_msg();
  1393.     }while(wrong);
  1394.  
  1395.     if(strlen(string))
  1396.     {
  1397.     string[0]=toupper(string[0]);
  1398.     if(string[0]=='X')
  1399.         ft_coords=XY;
  1400.     if(string[0]=='A')
  1401.         ft_coords=AMP;
  1402.     }
  1403.     printf("\n\n");
  1404.  
  1405.     if(ft_coords == AMP)
  1406.     {
  1407.     while(kbhit())
  1408.         getch();
  1409.     printf("The minimum amplitude for phase to be defined is %lf\n", min_amp);
  1410.     printf("(Lower amplitude signals have their phase set to 0)\n");
  1411.     printf("Enter a new minimum amplitude or <CR> to leave as is\n");
  1412.     (* get_string)(string);
  1413.     if(strlen(string))
  1414.         min_amp=atof(string);
  1415.     printf("\n\n");
  1416.  
  1417.     }
  1418.     while(kbhit())
  1419.     getch();
  1420.     printf("The frequency spectrum is set to ");
  1421.     if(ft_pos_neg==ALL)
  1422.     printf("display positive and negative frequencies\n");
  1423.     if(ft_pos_neg==POS)
  1424.     printf("display only positive frequencies\n");
  1425.     printf("Enter 'P' for positive frequencies only, 'A' for all frequencies, or <CR>\n");
  1426.     do
  1427.     {
  1428.     (* get_string)(string);
  1429.     if(strlen(string) && (toupper(string[0]) != 'P') && (toupper(string[0]) != 'A'))
  1430.         wrong=1;
  1431.     else
  1432.         wrong=0;
  1433.     if(wrong)
  1434.         error_msg();
  1435.     }while(wrong);
  1436.  
  1437.     if(strlen(string))
  1438.     {
  1439.     if(toupper(string[0])=='P')
  1440.         ft_pos_neg=POS;
  1441.     else
  1442.         ft_pos_neg=ALL;
  1443.     }
  1444.  
  1445. }
  1446.  
  1447.  
  1448. /* write_data() writes the data array to the file specified in STRING. */
  1449. /* N is th number of datapoints in ARRAY */
  1450.  
  1451. static void write_data(string,array, n)
  1452. char string[];
  1453. double array[];
  1454. int n;
  1455. {
  1456.     FILE *f;
  1457.     double minval, maxval;
  1458.     int i=0;
  1459.     char c;
  1460.  
  1461.     if(!fname_unused(string))
  1462.     {
  1463.     printf("WARNING!  You already have a filespec named %s.\n", string);
  1464.     printf("If you continue, that file will be overwritten.  Do you want to continue (y/N)?\n");
  1465.     c=binary_choice('N','Y');
  1466.     CLS;
  1467.     if(c=='N')
  1468.         return;
  1469.  
  1470.     }
  1471.    /* the I counter is to try to circumvent floppy disk opening errors */
  1472.     do
  1473.     {
  1474.     f=fopen(string,"w");
  1475.     i++;
  1476.     }while(f==NULL && i<4);
  1477.  
  1478.     if(f==NULL)
  1479.     {
  1480.     printf("Error opening data file %s\n.", string);
  1481.     perror("Program aborting");
  1482.     exit(-1);
  1483.     }
  1484.     minmax(array,n,&minval,&maxval);
  1485.     fprintf(f,"%d %lg %lg\n",n, minval, maxval);
  1486.     for(i=0;i<n;i++)
  1487.     fprintf(f,"%lg\n", array[i]);
  1488.     fclose(f);
  1489.  
  1490. }
  1491.  
  1492.